package com.yss.sofa.report.engine;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.yss.sofa.report.engine.cell.invisible.param.ParameterCell;
import com.yss.sofa.report.engine.cell.page.PageCell;
import com.yss.sofa.report.engine.cell.visible.VisibleCell;
import com.yss.sofa.report.engine.cell.visible.form.FormCell;
import com.yss.sofa.report.engine.cell.visible.result.ResultCell;
import com.yss.sofa.report.engine.core.Piston;

public final class EngineUtil {
	private EngineUtil(){}
//	/**
//	 * 获取模板中的所有数据源code
//	 * @param template 模板对象
//	 * @return code集合
//	 */
//	public static Set<String> getDbCodes(Template template){
//		Set<String> result=new HashSet<String>();
//		Set<DataSet> datasets;
//		datasets=template.getMainDatasets();
//		for(DataSet ds:datasets){
//			if(ds instanceof SqlDataSetCell){
//				result.add(((SqlDataSetCell)ds).getDb());
//			} else if(ds instanceof HeterogeneousSqlDataSetCell){
//				result.add(((HeterogeneousSqlDataSetCell)ds).getDb());
//			}
//		}
//		datasets=template.getFormDatasets();
//		for(DataSet ds:datasets){
//			if(ds instanceof SqlDataSetCell){
//				result.add(((SqlDataSetCell)ds).getDb());
//			} else if(ds instanceof HeterogeneousSqlDataSetCell){
//				result.add(((HeterogeneousSqlDataSetCell)ds).getDb());
//			}
//		}
//		return result;
//	}
//	/**
//	 * 获取模板中的所有参数元信息（主模板）
//	 * @param template 模板对象
//	 * @return <参数code,Parameter对象>
//	 */
//	public static Map<String,Parameter> getMetaParams(Template template){
//		Map<String,Parameter> result=new HashMap<String, Parameter>();
//		Set<? extends Parameter> params=template.getMainParams();
//		for(Parameter p:params){
//			result.put(p.getCode(),p);
//		}
//		return result;
//	}
//	/**
//	 * 获取主模板中的所有数据集
//	 * @param template 模板对象
//	 * @return <数据集code,DataSet对象>
//	 */
//	public static Map<String,DataSet> getMainDatasets(Template template){
//		Map<String,DataSet> result=new HashMap<String, DataSet>();
//		Set<? extends DataSet> datasets=template.getMainDatasets();
//		for(DataSet ds:datasets){
//			result.put(ds.getCode(),ds);
//		}
//		return result;
//	}
//	/**
//	 * 获取主模板中的所有数据集
//	 * @param template 模板对象
//	 * @return <数据集code,DataSet对象>
//	 */
	public static void SaveExcelExcludeSheets(InputStream in,String filename,String... names) throws IOException{
		XSSFWorkbook excel=new XSSFWorkbook(in);
		try {
			for(String name: names){
				XSSFSheet sheet=excel.getSheet(name);
				if(sheet==null){
					continue;
				}
				sheet.createRow(0).createCell(0).setCellValue("##");
			}
			excel.write(new FileOutputStream(filename));
		} finally {
			in.close();
			excel.close();
		}
	}
	public static Set<FormCell> getFormItems(Template template){
		Set<FormCell> result=new HashSet<FormCell>();
		Set<VisibleCell> cells=template.getFormCells();
		for(VisibleCell cell:cells){
			if(cell instanceof FormCell){
				result.add((FormCell) cell);
			}
		}
		return result;
	}
	public static Set<ParameterCell> getParameters(Template template){
		Set<ParameterCell> result=new HashSet<ParameterCell>();
		Set<Parameter> parameters=template.getMainParams();
		for(Parameter parameter:parameters){
			result.add((ParameterCell) parameter);
		}
		return result;
	}
	private static byte[] toExcelByte(Report report) throws Exception{
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		try {
			Engine.export(report, out, Const.FILE_TYPE_EXCEL);
			return out.toByteArray();
		} finally {
			out.close();
		}
	}
	public static Map<String,Serializable> toMap(Report report) throws Exception{
		Map<String,Serializable> map=new HashMap<String, Serializable>();
		map.put("report", report);
		map.put("sheets", report.getSheetMapping());
		map.put("code", report.getReportCode());
		map.put("name", report.getReportName());
		LinkedHashMap<String,String[][]> raws=Engine.raws(report);
		map.put("raw", raws.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("raws", raws);
		LinkedHashMap<String,Integer> rows=new LinkedHashMap<String,Integer>();
		LinkedHashMap<String,Integer> cols=new LinkedHashMap<String,Integer>();
		for(String to:report.getSheetMapping().values()){
			rows.put(to, report.getRowCount(to));
			cols.put(to, report.getColCount(to));
		}
		map.put("row", rows.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("rows", rows);
		map.put("col", cols.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("cols", cols);
		LinkedHashMap<String,Integer> titles=new LinkedHashMap<String,Integer>();
		LinkedHashMap<String,Integer> headers=new LinkedHashMap<String,Integer>();
		LinkedHashMap<String,Integer> details=new LinkedHashMap<String,Integer>();
		LinkedHashMap<String,Integer> footers=new LinkedHashMap<String,Integer>();
		for(String to:report.getSheetMapping().values()){
			PageCell page=report.getPage(to);
			titles.put(to,page.getTitleCount());
			headers.put(to,page.getHeaderCount());
			details.put(to,page.getRowCount()-page.getTitleCount()-page.getHeaderCount()-page.getFooterCount());
			footers.put(to,page.getFooterCount());
		}
		map.put("title", titles.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("titles", titles);
		map.put("header", headers.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("headers", headers);
		map.put("detail", details.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("details", details);
		map.put("footer", footers.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("footers", footers);
		LinkedHashMap<String,int[][]> multiRanges=new LinkedHashMap<String,int[][]>();
		for(String to:report.getSheetMapping().values()){
			Set<ResultCell> mergeCells=report.getRanges(to);
			int[][] ranges=new int[mergeCells.size()][4];
			int index=0;
			for(ResultCell cell:mergeCells){
				ranges[index][0]=cell.getRbegin();
				ranges[index][1]=cell.getCbegin();
				ranges[index][2]=cell.getRend();
				ranges[index][3]=cell.getCend();
				index++;
			}
			multiRanges.put(to,ranges);
		}
		map.put("ranges", multiRanges.get(report.getSheetMapping().get(Const.MAIN)));
		map.put("multi-ranges", multiRanges);
		Map<String, Serializable> params=report.getParams();
		params.put("CONSTS", (Serializable)report.getConsts());
		map.put("params", (Serializable)params);
		map.put("rawparams", (Serializable)report.getRawParams());
		map.put("excel", toExcelByte(report));
		return map;
	}
	

	public static boolean hasOOXMLHeader(InputStream inp) throws IOException {
		if (!inp.markSupported()) {
			inp = new PushbackInputStream(inp, 8);
		}
		inp.mark(4);
		byte header[] = new byte[4];
		int bytesRead = IOUtils.readFully(inp, header);
		if (inp instanceof PushbackInputStream) {
			PushbackInputStream pin = (PushbackInputStream) inp;
			pin.unread(header, 0, bytesRead);
		} else {
			inp.reset();
		}
		return bytesRead == 4
				&& header[0] == POIFSConstants.OOXML_FILE_HEADER[0]
				&& header[1] == POIFSConstants.OOXML_FILE_HEADER[1]
				&& header[2] == POIFSConstants.OOXML_FILE_HEADER[2]
				&& header[3] == POIFSConstants.OOXML_FILE_HEADER[3];
	}
	
	public static byte[] getFileBycode(Report report) throws Exception {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		
		Workbook excel=Piston.exportExcel(report);
//		Workbook excel = report.getExcel(false);
//
//		int index;
//		index = excel.getSheetIndex(Const.MAIN_META);
//		excel.removeSheetAt(index);
//		index = excel.getSheetIndex(Const.MAIN);
//		excel.removeSheetAt(index);
//		index = excel.getSheetIndex(Const.FORM_META);
//		excel.removeSheetAt(index);
//		index = excel.getSheetIndex(Const.FORM);
//		excel.removeSheetAt(index);
//		index = excel.getSheetIndex(Const.STYLE);
//		if (index >= 0) {
//			excel.removeSheetAt(index);
//		}
//		index = excel.getSheetIndex(Const.STYLE_META);
//		if (index >= 0) {
//			excel.removeSheetAt(index);
//		}
//		index = excel.getSheetIndex(Const.CUSTOM_UPDATE);
//		if (index >= 0) {
//			excel.removeSheetAt(index);
//		}
		excel.write(out);
		out.flush();
		excel.close();
		return out.toByteArray();
	}
	
//	public static Map<String,Serializable> toMap(Template template) throws Exception {
//		Map<String,Serializable> map=new HashMap<String, Serializable>();
//		//parameters
//		{
//			Set<Parameter> params=template.getMainParams();
//			map.put("parameters", (Serializable) params);
//		}
//		//main-datasets
//		{
//			Set<DataSet> datasets=template.getMainDatasets();
//			for(DataSet dataset:datasets){
//				Map<String,Serializable> ds=new HashMap<String, Serializable>();
//				ds.put("code", dataset.getCode());
//				ds.put("exec", dataset.getExec());
//				ds.put("params", (Serializable) dataset.getParams());
//				if(dataset instanceof NoneDataSetCell){
//					continue;
//				}
//				if(dataset instanceof SqlDataSetCell){
//					SqlDataSetCell _=(SqlDataSetCell)dataset;
//					ds.put("name", Const.name_REPORT_CELL_TYPE(_.getType()));
//					ds.put("db", _.getDb());
//					//...
//				}
//			}
//		}
//		return map;
//	}
	
//	public static int[] getValidateRowNumber(Report report) throws Exception {
//
//		return Piston.getValidateRowNumber(report);
//
//	}
}
